Skip to content

Sync x86_64 fcontext fixes#22584

Closed
kn1g78 wants to merge 3 commits into
php:masterfrom
kn1g78:fctx-x64-fix
Closed

Sync x86_64 fcontext fixes#22584
kn1g78 wants to merge 3 commits into
php:masterfrom
kn1g78:fctx-x64-fix

Conversation

@kn1g78

@kn1g78 kn1g78 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

This fixes the TLS stack protector save location, removes duplicated shadow stack handling, and adds CFI information for the make_fcontext trampoline.

@kn1g78
kn1g78 marked this pull request as ready for review July 4, 2026 01:50
@kn1g78
kn1g78 requested a review from TimWolla as a code owner July 4, 2026 01:50
@TimWolla
TimWolla removed their request for review July 4, 2026 10:14
@Girgias
Girgias requested a review from arnaud-lb July 4, 2026 11:24
@kn1g78

kn1g78 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

The intent of this PR is small: sync the upstream Boost.Context fixes relevant
to x86_64 Fiber/fcontext assembly.

The diff is larger because Zend/asm is a bundled upstream copy. Partial
cherry-picks fail Verify Bundled Files, so this had to be turned into a full
Boost.Context bundle sync from 1.86.0 to 1.91.0 by updating
boost-context.sh and
regenerating
Zend/asm. Most of the added lines are therefore upstream sync churn, not
new hand-written logic.

For reference, this was the original targeted x86_64 diff before converting it
into a full bundled sync:

diff --git a/Zend/asm/jump_x86_64_sysv_elf_gas.S b/Zend/asm/jump_x86_64_sysv_elf_gas.S
@@ -67,14 +67,6 @@ jump_fcontext:
      movq  %rbx, 0x30(%rsp)  /* save RBX */
      movq  %rbp, 0x38(%rsp)  /* save RBP */

-#if BOOST_CONTEXT_SHADOW_STACK
-    /* grow the stack to reserve space for shadow stack pointer(SSP) */
-    leaq  -0x8(%rsp), %rsp
-    /* read the current SSP and store it */
-    rdsspq  %rcx
-    movq  %rcx, (%rsp)
-#endif
-
  #if BOOST_CONTEXT_SHADOW_STACK
      /* grow the stack to reserve space for shadow stack pointer(SSP) */
      leaq  -0x8(%rsp), %rsp

diff --git a/Zend/asm/make_x86_64_sysv_elf_gas.S b/Zend/asm/make_x86_64_sysv_elf_gas.S
@@ -76,7 +76,7 @@ make_fcontext:
  #if defined(BOOST_CONTEXT_TLS_STACK_PROTECTOR)
      /* save stack guard */
      movq  %fs:0x28, %rcx    /* read stack guard from TLS record */
-    movq  %rcx, 0x8(%rsp)   /* save stack guard */
+    movq  %rcx, 0x8(%rax)   /* save stack guard */
  #endif

@@ -91,35 +91,6 @@ make_fcontext:
      /* will be entered after context-function returns */
      movq  %rcx, 0x38(%rax)

-#if BOOST_CONTEXT_SHADOW_STACK
-    /* Populate the shadow stack and normal stack */
-    /* get original SSP */
-    rdsspq  %r8
-    /* restore new shadow stack */
-    rstorssp  -0x8(%r9)
-    /* save the restore token on the original shadow stack */
-    saveprevssp
-    /* push the address of "jmp trampoline" to the new shadow stack */
-    /* as well as the stack */
-    call  1f
-    jmp  trampoline
-1:
-    /* save address of "jmp trampoline" as return-address */
-    /* for context-function */
-    pop 0x38(%rax)
-    /* Get the new SSP.  */
-    rdsspq  %r9
-    /* restore original shadow stack */
-    rstorssp  -0x8(%r8)
-    /* save the restore token on the new shadow stack.  */
-    saveprevssp
-
-    /* reserve space for the new SSP */
-    leaq  -0x8(%rax), %rax
-    /* save the new SSP to this fcontext */
-    movq  %r9, (%rax)
-#endif
-
  #if BOOST_CONTEXT_SHADOW_STACK
      /* Populate the shadow stack */

@@ -161,6 +132,8 @@ make_fcontext:
      ret /* return pointer to context-data */

  trampoline:
+    .cfi_startproc
+    .cfi_undefined rip
      /* store return address on stack */
      /* fix stack alignment */
      _CET_ENDBR
@@ -175,6 +148,7 @@ trampoline:
  #endif
      /* jump to context-function */
      jmp *%rbx
+    .cfi_endproc

Comment thread .github/scripts/download-bundled/boost-context.sh
@arnaud-lb arnaud-lb closed this in 9cefeea Jul 6, 2026
@arnaud-lb

Copy link
Copy Markdown
Member

Thank you @kn1g78!

andypost added a commit to skilld-labs/php-src that referenced this pull request Jul 16, 2026
The Boost.Context 1.91.0 sync (phpGH-22584) pulled in boostorg/context#325,
"fix cortex-m0 support to aapcs_elf_gas target", which adds a fallback
branch to make_fcontext/jump_fcontext for the Thumb-1 encoding limits of
ARMv6-M. The branch is correct for Cortex-M0 but is gated on
__ARM_ARCH >= 7, which is also false for classic ARMv6 in ARM state
(Alpine armhf, Raspberry Pi 1/Zero) -- targets that can encode every
instruction in the >= 7 branch and need none of the workaround.

Two consequences. make_fcontext took `ldr a2, =finish', materialising the
absolute address of finish through a literal pool in .text and emitting
R_ARM_ABS32 against .text. In a PIE link that becomes an R_ARM_RELATIVE
dynamic relocation inside the read-only text segment, tagging the binary
DT_TEXTREL. musl supports DT_TEXTREL only for DSOs it maps itself; the
main executable is kernel-mapped and handled by kernel_mapped_dso(),
which never inspects it, so ldso writes to a read-only page and dies with
SIGSEGV in do_relocs() before main(). Every SAPI, every invocation, no
output. glibc masks this by mprotecting the segment writable, which is
why only musl builds noticed.

Separately, jump_fcontext -- the hot path on every fiber switch -- grew
from 13 to 43 instructions on all ARMv6 builds, glibc included.

Gate on __ARM_ARCH_6M__ instead, exactly the target php#325 names. The
result emits byte-identical .text to 8.6.0alpha1 on every ARM target
except Cortex-M0, where it emits byte-identical .text to current master:
each target gets back the code it had before the regression, and M0 keeps
what php#325 added. armv7 and arm64 are unaffected either way.

Zend/asm is vendored and verified by the Verify Bundled Files workflow,
so carry the same diff in .github/scripts/download-bundled and re-apply
it from the sync script, as uriparser already does.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants